<script setup>
import {
  ref,
  inject,
  provide,
  onMounted,
  nextTick,
  watch,
  getCurrentInstance,
} from "vue";
import { isNil, set, get, cloneDeep } from "lodash";
import defaultOptions from "./js/defaultOptions.js";
import ColumnService from './js/columnService.js'

import {
  getComponentName,
  toHump,
  interactiveControl,
  handleFlatteningColumns,
} from "./js/utils";
import arrayComponentDefault from "./js/defaultArrayComponent.js";
import { loadDict, handlerCascader } from "./js/networkRequest.js";

// 组件导入
const containerList = import.meta.glob("./containerItem/*.vue", { eager: true });
const componentList = import.meta.glob("./formItem/*.vue", { eager: true });
const _this = getCurrentInstance()?.appContext;

// 注册组件
const registerComponents = (list, prefix) => {
  for (const [path, module] of Object.entries(list)) {
    const name = path.match(/([A-Za-z0-9_-]+)\.vue$/)?.[1] ?? "";
    const componentName = `${prefix}${toHump(name)}`;
    if (!_this.components[componentName]) {
      _this.app.component(componentName, module.default);
    }
  }
};

registerComponents(containerList, "Wd");
registerComponents(componentList, "Wd");

const props = defineProps({
  modelValue: { type: Object, default: () => ({}) },
  columns: { type: Array },
  options: { type: Object, default: () => ({}) },
});

const emit = defineEmits(["onSubmit", "update:modelValue"]);

const formModel = ref({});
const wdFormRef = ref(null);
const formLoading = ref(false);
const flatteningColumns = ref([]);
const cascaderList = ref([]);
const dictList = ref([]);
const formOptions = ref(Object.assign({}, cloneDeep(defaultOptions), props.options));

const validateForm = async () => await wdFormRef.value.validate();

const init = async () => {
  formLoading.value = true;
  handleFlatteningColumns(props.columns, flatteningColumns.value);

  for (const item of flatteningColumns.value) {
    if (isNil(formModel.value[item.dataIndex]) && !item.isChildrenForm) {
      formModel.value[item.dataIndex] = arrayComponentDefault.includes(item.formType) ? [] : undefined;
    }

    // 处理嵌套字段
    if (item.dataIndex.includes(".")) {
      const value = cloneDeep(formModel.value[item.dataIndex]);
      delete formModel.value[item.dataIndex];
      set(formModel.value, item.dataIndex, value);
    }

    // 字典处理
    if (!cascaderList.value.includes(item.dataIndex) && item.dict) {
      await loadDict(dictList.value, item);
    }

    await handlerCascader(
      get(formModel.value, item.dataIndex),
      item,
      flatteningColumns.value,
      dictList.value,
      formModel.value,
      false
    );
  }

  formLoading.value = false;
};

// 监听
watch(
  () => props.modelValue,
  (vl) => (formModel.value = vl),
  { immediate: true, deep: true }
);

watch(
  () => formModel.value,
  (vl) => {
    interactiveControl(vl, flatteningColumns.value);
    emit("update:modelValue", vl);
  },
  { deep: true }
);

onMounted(() => {
  if (formOptions.value.init) init();
});

const setDialogItemRef = async (ref) => {
  await nextTick(() => {
    if (ref?.getDataIndex) {
      dialogRefs.value[ref.getDataIndex()] = ref;
      if (!formModel.value[ref.getDataIndex()]) {
        formModel.value[ref.getDataIndex()] = {};
      }
    }
  });
};

const formSubmit = async () => {
  try {
    const valid = await validateForm();
    if (valid && !formLoading.value) {
      emit("onSubmit", formModel.value);
    }
  } catch (err) {
    console.error("表单提交出错:", err); // 已捕获
  }
};

provide("formModel", formModel);
provide("formLoading", formLoading);
provide("formOptions", formOptions.value);
provide("dictList", dictList);

defineExpose({
  init,
  getDictlist: () => dictList.value,
  getFormData: () => formModel.value,
  validateForm,
});

/**
 * 获取column属性服务类
 * @returns ColumnService
 */
const getColumnService = (strictMode = true) => {
  return new ColumnService(
    {
      columns: flatteningColumns.value,
      cascaders: cascaderList.value,
      dicts: dictList.value,
      refs: dialogRefs.value
    },
    strictMode
  )
}

provide('getColumnService', getColumnService)

</script>

<template>
  <div class="tw-w-full wd-global-form" v-loading="formLoading">
    <div
      v-if="formOptions.showFormTitle"
      :class="['wd-form-title', formOptions.formTitleClass]"
      :style="formOptions.formTitleStyle"
    >
      {{ formOptions.formTitle }}
    </div>
    <el-form
      ref="wdFormRef"
      :model="formModel"
      :label-position="formOptions.labelAlign"
      :inline="formOptions.layout"
      :label-width="formOptions.labelWith"
      :class="['wd-form', formOptions.customClass]"
      :size="formOptions.size"
      :validate-on-rule-change="false"
      :disabled="formOptions.disabled"
      :rules="options?.rules"
      @submit.prevent
    >
      <template v-for="(component, index) in columns" :key="index">
        <component
          :is="getComponentName(component.formType || 'input')"
          :component="component"
          :ref="setDialogItemRef"
        >
          <template v-for="slot in Object.keys($slots)" #[slot]="component">
            <slot :name="slot" v-bind="component" />
          </template>
        </component>
      </template>
    </el-form>
  </div>
</template>

<style scoped lang="less">
.wd-global-form {
  min-height: 10vh;
}
</style>